﻿package {
	import flash.display.DisplayObjectContainer;
	import flash.display.Graphics;
	import flash.display.GraphicsPath;
	import flash.display.GraphicsSolidFill;
	import flash.display.GraphicsStroke;
	import flash.display.IGraphicsData;
	import flash.display.IGraphicsStroke;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Vector3D;
	import flash.utils.getTimer;
	
	public class Main2 extends Sprite {
		private var main	:Sprite;
		private var rootMc	:MovieClip;
		private var rootObj	:Object;
		private var count		:int;
		private var graphicsData		:Vector.<IGraphicsData>;
		private var stroke				:GraphicsStroke;
		private var path				:GraphicsPath;
		private var directionVector		:Vector3D;
		private var rootRotation		:int = 0;
		
		public function Main2():void
		{
			this.x = Math.round(stage.stageWidth / 2);
			this.y = stage.stageHeight;
			this.scaleY = -1;
			
			rootObj = { thickness:1, level:1, parentObj:{rotationY:0, rotationZ:90, posRandom:1, length:0} };
			
			stroke = new GraphicsStroke(4,false,"normal","none","round",3,new GraphicsSolidFill(0x000000));
			path = new GraphicsPath(new Vector.<int>(), new Vector.<Number>());
			graphicsData = new Vector.<IGraphicsData>();
			graphicsData.push(stroke, path);
			
			stage.addEventListener(Event.ENTER_FRAME, redraw);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, update);
		}
		
		private function redraw(e:Event = null):void {
			count = 0;
			if (rootObj.thickness < 120)  {
				rootObj.thickness += 1;
				
			}
				graphics.clear();
				rootRotation += 6;
				updateLine(rootObj);
				trace("1 " + getTimer()/1000);
				drawLine(rootObj, new Vector3D(0, 0, 0));
				trace("2 " + getTimer() / 1000);
				graphics.drawGraphicsData(graphicsData);
				trace("3 " + getTimer()/1000);
				path.commands = new Vector.<int>();
				path.data = new Vector.<Number>();
				trace("count", count, "rootObj.thickness", rootObj.thickness, "at", getTimer() / 1000);
		}
		
		private function update(e:Event = null):void 
		{
			count = 0;
			graphics.clear();
			rootRotation = (stage.mouseX - stage.stageWidth/2)/stage.stageWidth * 360;
			updateLine(rootObj);
			drawLine(rootObj, new Vector3D(0, 0, 0));
			graphics.drawGraphicsData(graphicsData);
			trace("3 " + getTimer()/1000);
			path.commands = new Vector.<int>();
			path.data = new Vector.<Number>();
			trace("count",count,"rootObj.thickness",rootObj.thickness,"at",getTimer()/1000);
		}
		
		private function updateRotation(thisObj:MovieClip):void {
			(thisObj.getChildAt(0) as Shape).rotationY = -rootMc.rotationY;
			for (var i:int = thisObj.numChildren - 1; i >= 1; i--) { updateRotation.call(thisObj.getChildAt(i), thisObj.getChildAt(i)) };
		}
		
		private function drawLine(lineObj:Object, sumVector:Vector3D):void {
		private function drawLine(lineObj:Object, sumVector:Vector3D):void {
			count ++;
			var point:Point = Point.polar(1, lineObj.rotationZ * Math.PI / 180);
			var point2:Point = Point.polar(point.x, (lineObj.rotationY + rootRotation) * Math.PI / 180);
			var currentVector:Vector3D = new Vector3D(point2.x, point.y, point2.y );
			currentVector.scaleBy(lineObj.length/100);
			
			point = Point.polar(1, lineObj.parentObj.rotationZ * Math.PI / 180);
			point2 = Point.polar(point.x, (lineObj.parentObj.rotationY + rootRotation) * Math.PI / 180);
			var parentVector:Vector3D = new Vector3D(point2.x, point.y, point2.y );
			parentVector.scaleBy(lineObj.parentObj.length * lineObj.posRandom/100);
		//	trace("sumVector ",sumVector);
		//	trace("parentVector ",parentVector);
			
			parentVector.incrementBy(sumVector);
			currentVector.incrementBy(parentVector);
		//	trace(parentVector, currentVector);
			
			path.commands.push(1, 2);
			path.data.push(parentVector.x, parentVector.y, currentVector.x, currentVector.y);
			
			//graphics.lineStyle(lineObj.thickness/10);
			//graphics.moveTo( sumVector.x, sumVector.y );
			//graphics.lineTo( currentVector.x, currentVector.y );
			
			for (var i:int = 0; lineObj["child"+i] != null; i++) { drawLine(lineObj["child"+i], parentVector) };
		}
		
		public function updateLine(thisObj:Object):Object {
			if (thisObj.lengthRandom == null) {
				thisObj.lengthRandom = 6 + Math.round(Math.random() * 40)/10;
				thisObj.thicknessReduction = 6 + Math.round(Math.random() * 20)/10;
				thisObj.thicknessMultiplication = Math.round(7 + Math.random() * 3)/10;
				thisObj.posRandom = (thisObj.i <= 1) ? 1 - Math.random() * 0.3 * thisObj.i: Math.round(4 + Math.random() * 6) / 10;
				if(!thisObj.rotationY) thisObj.rotationY = Math.round( (thisObj.level - 1) * -30 + Math.random() * (((thisObj.level - 1) * 60)));
				if(!thisObj.rotationZ) thisObj.rotationZ = thisObj.parentObj.rotationZ + Math.round( (thisObj.level - 1) * -30 + Math.random() * (((thisObj.level - 1) * 60)));
			}
			thisObj.length = Math.round( thisObj.lengthRandom * (12 * thisObj.thickness));
			if (thisObj.thickness > 6 && thisObj.level < 6) {
				if (thisObj.child0 == null) for (var i:int = (thisObj.level <= 2)? thisObj.level + 1 : 4; i >= 0; i--) { thisObj["child" + i] = {level:thisObj.level+1, parentObj:thisObj, i:i} };
				for (var j:int = 0; thisObj["child"+j] != null; j++) { 
					var lineObj:Object = thisObj["child"+j];
					lineObj.thickness = ((thisObj.thickness * lineObj.thicknessMultiplication - lineObj.thicknessReduction) > 0.5)? (thisObj.thickness * lineObj.thicknessMultiplication - lineObj.thicknessReduction) : 0.5;
					updateLine(lineObj);
					
				}
			}
			return thisObj;
		}
	}
}